package com.liquidhub.tests;

import java.util.*;
import java.util.concurrent.*;

public  class GarbageCollectorTest {
/*  interesting note : if consumer rate falls below producer rate this can fail
	since the implicit number of allowed nodes is MAX_INT.  
	Granted this is a large number, but still, boundary test case. Correct by design :)
 */
	private LinkedBlockingQueue<Object> _queue = new LinkedBlockingQueue<Object>(); 
 	private ArrayList<Object> _Cleanup = new ArrayList<Object>();
	private int _sleep = 10;
	private int _ratio = 3000000;
	private int _numproducers = 4;

	public GarbageCollectorTest(int rate, int numproducers, int cleanupratio) {
		_sleep = rate;
		_ratio = cleanupratio;
		_numproducers = numproducers;
	}

	public void cleanup() {
		while (true)
		{
			try {
				Thread.sleep(_ratio * _sleep);
				{
						// clear out the queue and fire the gc
                    _Cleanup.clear();
                    Runtime.getRuntime().gc();
				}
			} catch (java.lang.InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
        /// <summary>
        /// just sits in a loop and adds random ojbjects to a queue
        /// </summary>
	public void producer() {
		Random r = new Random();
		while (true)
		{
			try {
					//create a relative random sized array and add it here
				int cap = r.nextInt(3200);
				StringBuffer sb = new StringBuffer(cap);
				while (cap-- > 0)
				{
					sb.append(cap % 26);
				}
				_queue.put(sb);
				// sleep for a while
				int s = r.nextInt(_sleep*2);
				Thread.sleep(s);
			} catch (java.lang.InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
        
	public void consumer() {
		Random r = new Random();
		while (true)
		{
			try {
					// assume that the processor is at least slightly faster than the producer
					// but randomize it a bit so it averages out
				Thread.sleep(_sleep/_numproducers/2);
				Object o = _queue.take();
                if(_ratio > 0) _Cleanup.add(o); // ok since i havea  single consumer for this test case
				o = null;
			} catch (java.lang.InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public void go() {
		final GarbageCollectorTest gct = this;
		if(_ratio > 0)
			new Thread(new Runnable() {public void run() {gct.cleanup();}}).start();
		new Thread(new Runnable() {public void run() {gct.consumer();}}).start();
		for (int i = 0; i < _numproducers; i++)
			new Thread(new Runnable() {public void run() {gct.producer();}}).start();
	}
   
	public static void main(String[] args) {
			// a little different in java i guess
			// we need to start different runnables on thread
			// but since we can pas apramters we cn cheat that wa
		int rate = 5, numproducers = 16, cleanupratio=000;
		if (args.length > 0) rate = Integer.parseInt(args[0]);
		if (args.length > 1) numproducers = Integer.parseInt(args[1]);
		if (args.length > 2) cleanupratio = Integer.parseInt(args[2]);
		
		GarbageCollectorTest t = new GarbageCollectorTest(rate, numproducers,cleanupratio);
		t.go();
	}
}

